/*
PearReview - The peer review assistant.
Copyright (C) 2009  Dimitrij Pankratz, Anton Musichin
http://www.pearreview.com, info@pearreview.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package com.pearreview.reviewerplugin;

import java.awt.BorderLayout;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.LayoutStyle;
import javax.swing.SwingWorker;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.pearreview.application.Messages;
import com.pearreview.application.SpringGlassPane;
import com.pearreview.reviewerplugin.io.PDFReportWriter;
import com.pearreview.ui.BottomButtonPanel;
import com.pearreview.ui.DurationSpinner;
import com.pearreview.ui.FadingTextArea;
import com.pearreview.ui.FormLabel;
import com.pearreview.ui.HeadingLabel;
import com.pearreview.ui.clock.ScribeClock;
import com.pearreview.util.PDFFileFilter;;

/**
 * This panel stores the last form of the reviewer mode.
 * The user can write comments, impression, recommendation and export
 * the report.
 *
 */
public class FinalPanel extends ReviewerPanel {

	private static final long serialVersionUID = 9179999572165834539L;
	private JScrollPane scrollPane2;
	private FadingTextArea recommendation;
	private FormLabel recommendationLabel;
	private JScrollPane scrollPane3;
	private FadingTextArea impression;
	private FormLabel impressionLabel;
	private JButton exportReportBtn;
	private JPanel container;
	private HeadingLabel heading;
	private JCheckBox printImagesCheck;
	private DurationSpinner prepTime;
	private FormLabel prepTimeLabel;
	
	private File lastDir;
	
	private Report report;
	
	private SpringGlassPane glassPane;
	private BottomButtonPanel bottom;
	
	private ScribeClock clock;
	
	public FinalPanel(SpringGlassPane glassPane) {
		this.glassPane = glassPane;
		initComponents();
	}
	
	@Override
	public void applyReport() {
		if(report == null) {
			report = new Report();
		}
		
		report.setRecommendation(getRecommendation());
		report.setImpression(getImpression());
		report.setPreparationTime(getPreparationTime());
	}
	
	public long getPreparationTime() {
		return clock.getPassedTime();
	}
	
	public void setPreparationTime(Long time) {
		long pTme = time == null ? 0 : time;
		prepTime.setDuration(pTme);
		clock.setPassedTime(pTme);
	}

	@Override
	public void setNextViewAction(Action action) {
		bottom.setNextViewAction(action);
	}
	
	@Override
	public void setPreviousViewAction(Action action) {
		bottom.setPreviousViewAction(action);

	}

	@Override
	public void setReport(Report report) {
		this.report = report;
		
		if (report != null) {
			setRecommendation(report.getRecommendation());
			setImpression(report.getImpression());
			setPreparationTime(report.getPreparationTime());
		} else {
			setPreparationTime(0L);
			setRecommendation(null);
			setImpression(null);
		}
	}
	
	public void setClock(ScribeClock clock) {
		this.clock = clock;
	}
	
	public String getRecommendation() {
		return recommendation.getText();
	}
	
	public void setRecommendation(String recommendation) {
		this.recommendation.setText(recommendation);
	}
	
	public String getImpression() {
		return impression.getText();
	}
	
	public void setImpression(String impression) {
		this.impression.setText(impression);
	}
	
	public File getLastExportFile() {
		return lastDir;
	}
	
	public void setLastExportFile(File file) {
		lastDir = file;
	}
	
	public boolean isPrintImagesSelected() {
		return printImagesCheck.isSelected();
	}
	
	public void setPrintImagesSelected(boolean b) {
		printImagesCheck.setSelected(b);
	}
	
	public static File getDefaultExportFile() {
		return new File("report_" + 
				new SimpleDateFormat("dd.MM.yyyy").format(new Date()));
	}
	
	private void initComponents() {
		setFont(new Font("Tahoma", Font.PLAIN, 12));
		scrollPane2 = new JScrollPane();
		recommendation = new FadingTextArea();
		recommendationLabel = new FormLabel();
		scrollPane3 = new JScrollPane();
		impression = new FadingTextArea();
		impressionLabel = new FormLabel();
		exportReportBtn = new JButton();
		container = new JPanel();
		
		prepTime = new DurationSpinner();
		prepTime.getModel().addChangeListener(new ChangeListener() {
			@Override
			public void stateChanged(ChangeEvent e) {
				clock.setPassedTime(prepTime.getDuration());
				clock.pauseTimer();
			}
		});
		prepTimeLabel = new FormLabel(Messages.getString(
			"PearReview.Scribe.attendees.preparation_time_short"));
		
		printImagesCheck = new JCheckBox();
		
		ArrayList<JComponent> sameSizeBtns = new ArrayList<JComponent>();
		sameSizeBtns.add(exportReportBtn);

		//======== this ========

		//======== scrollPane2 ========
		{
			scrollPane2.setViewportView(recommendation);
		}

		//---- recommendationLabel ----
		recommendationLabel.setText(
				getLocalizedString("recommendationLabel.text"));
		recommendation.setFont(getFont());

		//======== scrollPane3 ========
		{

			scrollPane3.setViewportView(impression);
			impression.setFont(getFont());
		}

		//---- impressionLabel ----
		impressionLabel.setText(getLocalizedString("impressionLabel.text"));

		//---- exportReportBtn ----
		exportReportBtn.setAction(new CreateReportAction());
		exportReportBtn.setText(
				Messages.getString("PearReview.Reviewer.final.export"));
		exportReportBtn.setFont(getFont());
		exportReportBtn.setIcon(
				new ImageIcon(getClass().getResource("images/pdf.png")));
		
		printImagesCheck.setOpaque(false);
		printImagesCheck.setText(getLocalizedString("print_images"));
		printImagesCheck.setFont(getFont());
		printImagesCheck.setSelected(false);
		
		calcPreferredSize(sameSizeBtns);
		
		container.setOpaque(false);

		GroupLayout layout = new GroupLayout(container);

		container.setLayout(layout);
		layout.setHorizontalGroup(
			layout.createParallelGroup()
				.addGroup(layout.createSequentialGroup()
					.addContainerGap()
					.addGroup(layout.createParallelGroup()
						.addComponent(recommendationLabel, 
								GroupLayout.PREFERRED_SIZE, 
								137, 
								137)
						.addComponent(impressionLabel, 
								GroupLayout.PREFERRED_SIZE, 
								137, 
								137)
						.addComponent(prepTimeLabel, 
								GroupLayout.PREFERRED_SIZE, 
								137, 
								137))
					.addGroup(layout.createParallelGroup()
						//.addGroup(layout.createSequentialGroup()
							//.addComponent(printImagesCheck)
							//.addContainerGap())
						.addGroup(layout.createParallelGroup()
							.addGroup(layout.createSequentialGroup()
								.addComponent(exportReportBtn,
										GroupLayout.PREFERRED_SIZE,
										GroupLayout.PREFERRED_SIZE,
										GroupLayout.PREFERRED_SIZE)
								.addGap(10)
								.addComponent(printImagesCheck)
								.addContainerGap())
							.addGroup(layout.createSequentialGroup()
								.addGroup(layout.createParallelGroup(
										GroupLayout.Alignment.TRAILING)
										.addGroup(layout.createParallelGroup()
									.addComponent(prepTime,
											GroupLayout.PREFERRED_SIZE,
											150,
											GroupLayout.PREFERRED_SIZE)
									.addComponent(scrollPane3,
											GroupLayout.DEFAULT_SIZE,
											300,
											Short.MAX_VALUE))
									.addComponent(scrollPane2, 
											GroupLayout.Alignment.LEADING, 
											GroupLayout.DEFAULT_SIZE, 
											300, 
											Short.MAX_VALUE))
								.addGap(10)))))
		);
		layout.setVerticalGroup(
			layout.createParallelGroup()
				.addGroup(layout.createSequentialGroup()
					.addContainerGap()
					.addGroup(layout.createParallelGroup()
						.addGap(10))
					.addGroup(layout.createParallelGroup()
						.addComponent(scrollPane2, 
								GroupLayout.PREFERRED_SIZE, 
								100, 
								GroupLayout.PREFERRED_SIZE)
						.addComponent(recommendationLabel,
								GroupLayout.PREFERRED_SIZE, 
								GroupLayout.DEFAULT_SIZE, 
								GroupLayout.PREFERRED_SIZE))
					.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
					.addGroup(layout.createParallelGroup()
							.addGroup(layout.createSequentialGroup()
							.addComponent(scrollPane3, 
									GroupLayout.PREFERRED_SIZE, 
									100, 
									GroupLayout.PREFERRED_SIZE))
						.addComponent(impressionLabel, 
								GroupLayout.PREFERRED_SIZE, 
								GroupLayout.DEFAULT_SIZE, 
								GroupLayout.PREFERRED_SIZE))
					.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
					.addGroup(layout.createParallelGroup()
							.addGroup(layout.createSequentialGroup()
							.addComponent(prepTime, 
									GroupLayout.PREFERRED_SIZE, 
									GroupLayout.PREFERRED_SIZE, 
									GroupLayout.PREFERRED_SIZE))
						.addComponent(prepTimeLabel, 
								GroupLayout.PREFERRED_SIZE, 
								GroupLayout.DEFAULT_SIZE, 
								GroupLayout.PREFERRED_SIZE))
					.addGap(18, 18, 18)
					.addGroup(layout.createParallelGroup()
							.addComponent(exportReportBtn,
									GroupLayout.PREFERRED_SIZE,
									GroupLayout.PREFERRED_SIZE,
									GroupLayout.PREFERRED_SIZE)
							.addComponent(printImagesCheck))
					.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
					.addContainerGap(10, Short.MAX_VALUE))
		);
		
		setLayout(new BorderLayout());
		heading = new HeadingLabel(Messages.getString(
				"PearReview.Reviewer.tabs.final"));
		add(heading, BorderLayout.NORTH);
		
		add(container, BorderLayout.CENTER);
		
		bottom = new BottomButtonPanel();
		add(bottom, BorderLayout.SOUTH);
	}
	
	/**
	 * Returns localized string of this component
	 * @param key key of string to localize
	 * @return localized string of this component
	 */
	private static String getLocalizedString(String key) {
		return Messages.getString("PearReview.Scribe.export." + key);
	}
	
	/**
	 * If true, sets the loading panel with animation to the bottom of the 
	 * current panel and removes instead the bottom navigation buttons.
	 * 
	 * Otherwise removes the loading panel and puts the navigation buttons
	 * back.
	 * 
	 * @param loading
	 */
	private void setLoading(boolean loading) {
		if (loading) {
			glassPane.setLoadingMessage(
					Messages.getString("PearReview.Reviewer.final.exporting"));
			glassPane.showLoadingPanel(true);
		} else {
			glassPane.showLoadingPanel(false);
		}
	}
	
	private class CreateReportAction extends AbstractAction {
		private static final long serialVersionUID = -3709598163071113321L;
		@Override
		public void actionPerformed(ActionEvent e) {
			
			final JFileChooser saveDialog = new JFileChooser();
			saveDialog.setMultiSelectionEnabled(false);
			saveDialog.setAcceptAllFileFilterUsed(false);
			
			PDFFileFilter pdfFilter = new PDFFileFilter();
			
			saveDialog.setFileFilter(pdfFilter);
			saveDialog.setCurrentDirectory(lastDir);
			
			saveDialog.setSelectedFile(
					lastDir == null ? getDefaultExportFile() : lastDir);
			
			glassPane.setFaded(true);
			int ret = saveDialog.showSaveDialog(FinalPanel.this);
			glassPane.setFaded(false);
			
			if (JFileChooser.APPROVE_OPTION != ret)
				return;
			
			lastDir = saveDialog.getSelectedFile();
			if(!pdfFilter.accept(lastDir)) {
				String fileName = lastDir.getName();
				fileName += PDFFileFilter.EXTENSION;
				lastDir = new File(lastDir.getParent(), fileName);
			}
			
			final PDFReportWriter reportWriter;
			
			reportWriter = new PDFReportWriter();
			
			SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
				@Override
				protected Void doInBackground() throws Exception {
					setLoading(true);
					
					FileOutputStream fos;
					BufferedOutputStream bos = null;
					
					reportWriter.setPrintImages(printImagesCheck.isSelected());
			
					try {
						fos = new FileOutputStream(lastDir);
						bos = new BufferedOutputStream(fos);
						applyReport();
						reportWriter.write(report, fos);
						
						bos.close();
						
						Desktop.getDesktop().browse(lastDir.toURI());
					} catch (FileNotFoundException e1) {
						JOptionPane.showMessageDialog(FinalPanel.this,
								//TODO localize etc.
								e1.getMessage(), 
								Messages.getString("PearReview.error"), 
								JOptionPane.ERROR_MESSAGE);
					} catch (Exception e1) {
						// TODO error message?!
						e1.printStackTrace();
						try {
							bos.close();
						} catch (IOException e2) {
							JOptionPane.showMessageDialog(FinalPanel.this,
									//TODO localize etc. 
									e2.getMessage(), 
									Messages.getString("PearReview.error"),
									JOptionPane.ERROR_MESSAGE);
						}
						JOptionPane.showMessageDialog(FinalPanel.this,
								//TODO localize etc. 
								e1.getMessage(),
								Messages.getString("PearReview.error"),
								JOptionPane.ERROR_MESSAGE);
					}
					
					setLoading(false);
					return null;
				}
			};
			
			worker.execute();
		}
	}
	
	private Dimension calcPreferredSize(ArrayList<JComponent> list) {
		Dimension biggestDim = new Dimension(1,1);
		for (JComponent comp: list) {
			Dimension currentDim = comp.getPreferredSize();
			if (currentDim.height > biggestDim.height)
				biggestDim.height = currentDim.height;
			if (currentDim.width > biggestDim.width)
				biggestDim.width = currentDim.width;
		}
		
		for (JComponent comp: list) {
			comp.setPreferredSize(biggestDim);
		}
		
		return biggestDim;
	}
}
